package cate.game.client.msg;

import cate.game.role.Role;

import java.util.*;
import java.util.function.Function;

/** 待发送的消息列表，会尽可能把可以合并的消息给合并了 */
public class MergeMsgSender {

    private List<MergeMsgOutput> list;

    public boolean isEmpty(){
        return list == null || list.isEmpty();
    }

    public static <T> T batchSend(Role role, Function<MergeMsgSender, T> function) {
        MergeMsgSender sender = new MergeMsgSender();
        T t = function.apply(sender);
        sender.send(role, true);
        return t;
    }

    public MergeMsgSender add(MergeMsgOutput msg) {
        if (list == null) {
            list = new ArrayList<>();
        }
        list.add(msg);
        return this;
    }

    @SuppressWarnings("unchecked")
    public void send(Role role, boolean now) {
        if (list == null || list.isEmpty() || role.entering) {
            return;
        }
        Map<Class<? extends MergeMsgOutput>, List<MergeMsgOutput>> r = new LinkedHashMap<>();
        for (MergeMsgOutput an : list) {
            boolean beMerged = false;
            if (r.containsKey(an.getClass())) {
                for (MergeMsgOutput ann : r.get(an.getClass())) {
                    if (ann.merge(an)) {
                        beMerged = true;
                        break;
                    }
                }
            } else {
                r.put(an.getClass(), new ArrayList<>());
            }
            if (!beMerged) {
                r.get(an.getClass()).add(an);
            }
        }
        List<MergeMsgOutput> msgs = new ArrayList<>();
        r.values().forEach(msgs::addAll);
        msgs.sort(Comparator.comparingInt(MergeMsgOutput::ordinal));
        for (MergeMsgOutput msg : msgs) {
            msg.send(role);
        }
        if (now && role.getCc() != null) {
            role.getCc().flush();
        }
    }

    public static void handle(MergeMsgSender sender, MergeMsgOutput msg, Role role) {
        if (sender != null) {
            sender.add(msg);
        } else {
            msg.sendNow(role);
        }
    }
}
